# -*- coding:utf-8 -*-

## =====================================================================
## Copyright (C) 2007-2011  Jean-Philippe GOLAY
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
## =====================================================================


from Tkinter import *
import Pmw
import time
from tkMessageBox import *
import tkFont

from Persistance import *
from iCalendar import CalendarGUI
from iNotes import NotesGUI
from iStay import BillStayGUI
from iTax import TaxListGUI
from iReference import ReferenceListGUI
from iPlace import PlaceListGUI
from iPerson import PersonListGUI
from iBillPDF import BillPDF

class BillGUI(Toplevel):
	def __init__(self, parent=None, balloon=None, path=None, log=None):
		Toplevel.__init__(self, parent)
		self.parent=parent
		self.grab_set()
		self.transient(self.master)
		self.resizable(width=False, height=False)
		self.title(u"Pièces de vente")
		self.balloon=balloon
		self.numberFT = tkFont.Font(family="Helvetica", size=10, weight="bold")
		self.imgSave=PhotoImage(file="img/save_icon.gif")
		self.imgDelete=PhotoImage(file="img/delete_icon.gif")
		self.imgCalendar=PhotoImage(file="img/calendar.gif")
		self.imgNotes=PhotoImage(file="img/edit.gif")
		self.imgSearch=PhotoImage(file="img/search_icon.gif")
		self.imgLinks=PhotoImage(file="img/links_icon.gif")
		self.imgCalculate=PhotoImage(file="img/undo_icon.gif")
		self.imgPrint=PhotoImage(file="img/print_icon.gif")
		self.hoursListCB = Glob.HOURS_LIST
		self.minutesListCB = Glob.MINUTES_LIST
		self.defaultTaxID=1 # TODO a recuperer dans l'object preference todo
		self.path=path
		self.log=log
		# Afficher un icon personnalisé
		try:
			if os.name =="posix":
				img = PhotoImage(file=self.path+"/icons/Bill-icon.gif")
				self.tk.call("wm", "iconphoto", self._w, img)
			else:
				self.iconbitmap(default=self.path+"/icons/Bill-icon.gif")
		except TclError:
			self.log.warning("Le window manager ne supporte pas l'icône que je veux lui mettre...")
		self.log.info("\tBillGUI\tStart")
		self.makeBill()

	# DEBUT de la gestion du module Bill ------------------------------------------------------------------------------------------------------------------
	def clearFieldBill(self):
		# Mise a zéro des champs
		today = datetime.date.today()
		delay = datetime.timedelta(days=30)
		dueDate = today+delay
		self.billValues[0].set(today.strftime("%d/%m/%Y" ))
		self.billValues[1].set("")
		self.billValues[2].set("C")
		self.billValues[3].set("")
		self.billValues[4].set("")
		self.billValues[5].set(dueDate.strftime("%d/%m/%Y" ))
		self.billValues[6].set("0.00")
		self.billValues[7].set("0.00")
		self.billValues[8].set("0.00")
		self.billValues[9].set("")
		self.billValues[10].set("E")
		self.billValues[11].set("")
		self.billValues[12].set("")
		self.billValues[13].set("")
		# Remise à zéro des ComboBox
		self.billSortCB.selectitem(0)
		self.billStatusCB.selectitem(0)
		self.listObject=[Person, Place, Bill, Reference, Tax]
		self.billPaymentBillBt.config(state=DISABLED)
		self.billChasingUpBt.config(state=DISABLED)
		self.billStayBillBt.config(state=DISABLED)

	def getBillNumber(self):
		result = NumberBill.select()
		n = time.strftime("%Y%m" ,time.localtime())+str(1000+result.count())
		NumberBill(number=n, createDate=datetime.datetime.now())
		return n

	def selectBill(self, event):
		if self.listBill.get(0)!="":
			result = Bill.select(Bill.q.id==self.idListBill[int(self.listBill.curselection()[0])])
			for row in result:
				self.selectedBill = row
			self.listObject[0]=self.selectedBill.customer
			self.listObject[1]=self.selectedBill.place
			self.listObject[2]=self.selectedBill
			self.billValues[3].set(self.listObject[0].fname+" - "+self.listObject[0].lname)
			if self.listObject[1] != None:self.billValues[4].set(self.listObject[1].company)
			if self.selectedBill.reference != None:self.billValues[1].set(self.selectedBill.reference)
			if self.selectedBill.sort != None:self.billValues[2].set(self.selectedBill.sort)
			if self.selectedBill.tHTPrice != None:self.billValues[6].set("%.2f" % self.selectedBill.tHTPrice)
			if self.selectedBill.tTaxPrice != None:self.billValues[7].set("%.2f" % self.selectedBill.tTaxPrice)  
			if self.selectedBill.tTCPrice != None:self.billValues[8].set("%.2f" % self.selectedBill.tTCPrice)
			if self.selectedBill.status != None:self.billValues[10].set(self.selectedBill.status)
			if self.selectedBill.notes != None:self.billValues[9].set(self.selectedBill.notes)
			if self.selectedBill.date != None:
				# Affichage de la date
				self.billValues[0].set(self.selectedBill.date.strftime("%d/%m/%Y"))
			if self.selectedBill.dueDate != None:
				# Affichage de la date d'écheance
				self.billValues[5].set(self.selectedBill.dueDate.strftime("%d/%m/%Y"))
			# Affichage de Sort dans la ComboBox
			sort = ((u"C", 0),(u"D", 1),(u"F", 2),(u"A", 3),) 
			for n in sort:
				if n[0] == self.selectedBill.sort: self.billSortCB.selectitem(n[1])
			# Affichage de Status dans la ComboBox
			status = ((u"E", 0),(u"P", 1),(u"L", 2),(u"R", 3),(u"A", 4),) 
			for n in status:
				if n[0] == self.selectedBill.status: self.billStatusCB.selectitem(n[1])
			# Affichage de la présence de Paiements lié a ce séjour
			result = PaymentBill.select(PaymentBill.q.bill==self.selectedBill)
			count=0
			for row in result:
				count+=1
			if count < 2:
				self.billValues[12].set(str(count)+u" Paiement")
			else:
				self.billValues[12].set(str(count)+u" Paiements")
			# activation du bouton ParkingChoice rattaché
			self.billPaymentBillBt.config(state=NORMAL)
			# Affichage de la présence de Relance
			result = ChasingUp.select(ChasingUp.q.bill==self.selectedBill)
			count=0
			for row in result:
				count+=1
			if count < 2:
				self.billValues[13].set(str(count)+u" Relance")
			else:
				self.billValues[13].set(str(count)+u" Relances")
			# activation du bouton Resident rattaché
			self.billChasingUpBt.config(state=NORMAL)
			# Affichage de la présence de BillBill lié a cette facture
			result = StayBill.select(StayBill.q.bill==self.selectedBill)
			count=0
			for row in result:
				count+=1
			if count < 2:
				self.billValues[11].set(str(count)+u" Séjour")
			else:
				self.billValues[11].set(str(count)+u" Séjours")
			# activation du bouton BillBill rattaché
			self.billStayBillBt.config(state=NORMAL)
			# activation du bouton supprimer
			self.deleteBillBt.config(state=NORMAL)
			# activation du bouton imprimer
			self.printBillBt.config(state=NORMAL)
			self.searchLineBill()

	def searchBill(self, event=None):
		if self.searchBillValue.get() != "":
			self.listBill.delete(0,END)
			self.idListBill = []
			result = Bill.select(Bill.q.reference.startswith(self.searchBillValue.get().encode("utf-8")), orderBy=Bill.q.date)
			for row in result:
				self.listBill.insert(END, row.reference+" - "+row.sort+" - "+row.customer.lname+" - "+row.customer.fname+" - "+row.date.strftime("%d/%m/%Y")+" - "+row.status+" - "+row.place.company)
				self.idListBill.append(row.id)
		else:
			self.listBill.delete(0,END)
			self.idListBill = []
			result = Bill.select(orderBy=Bill.q.date)
			for row in result:
				self.listBill.insert(END, row.reference+" - "+row.sort+" - "+row.customer.lname+" - "+row.customer.fname+" - "+row.date.strftime("%d/%m/%Y")+" - "+row.status+" - "+row.place.company)
				self.idListBill.append(row.id)

	def makeBill(self):
		topFrame = Frame(self)
		leftFrame = Frame(topFrame)
		# Fiche Bill  (présentation colonne de gauche)
		Label(leftFrame, text=u"Entête").pack(side=TOP, fill=X)
		# Création des champs a renseigner pour un object Bill
		billStatusListCB = (u"En cours", u"Payé", u"Litige", u"Remplacé", u"Annulé")  
		billSortListCB = (u"Commande", u"Devis", u"Facture", u"Avoir") 
		billLabels = (u"Date", u"Référence", u"Type pièce", u"Client", u"Résidence", u"Date d'écheance", u"Total HT", u"Total taxes", u"Total TTC", u"Notes", u"Status", u"Séjours rattachés", u"Paiements rattachés", u"Relances rattachées")
		self.billValues = [StringVar(), StringVar(), StringVar(), StringVar(), StringVar(), StringVar(), StringVar(), StringVar(), StringVar(), StringVar(), StringVar(), StringVar(), StringVar(), StringVar()]
		count = 0
		for name in billLabels:
			f = Frame(leftFrame)
			if count == 0: # Date du documents
				Label(f, width=18, text=name, anchor=W).pack(side=LEFT)
				Entry(f, textvariable=self.billValues[count], width=21).pack(side=LEFT, fill=X)
				myCal1=Button(f, image=self.imgCalendar, command=lambda x=self.billValues[count]:self.ctrlCalendar(x), padx=4, pady=1)
				myCal1.pack(side=LEFT)
				self.balloon.bind(myCal1, u"Calendrier")
			elif count == 2: # Type de piece
				Label(f, width=18, text=name, anchor=W).pack(side=LEFT)
				self.billSortCB=Pmw.ComboBox(f, selectioncommand=self.billSort, scrolledlist_items=billSortListCB, listheight=100)
				self.billSortCB._entryfield._entryFieldEntry.config( width=21)
				self.billSortCB.pack(side=LEFT, fill=X)
				self.billSortCB.selectitem(0)
				self.billValues[count].set(u"C")
			elif count == 3: # Client
				Label(f, width=18, text=name, anchor=W).pack(side=LEFT)
				Entry(f, textvariable=self.billValues[count], width=21, state=DISABLED, bd=0, disabledforeground="black").pack(side=LEFT, fill=X)
				myCustomer=Button(f, image=self.imgSearch, command=lambda x=self.billValues[count]:self.ctrlListPerson(x), padx=4, pady=1)
				myCustomer.pack(side=RIGHT)
				self.balloon.bind(myCustomer, u"Séléctionner un Client")
			elif count == 4: # Résidence
				Label(f, width=18, text=name, anchor=W).pack(side=LEFT)
				Entry(f, textvariable=self.billValues[count], width=21, state=DISABLED, bd=0, disabledforeground="black").pack(side=LEFT, fill=X)
				myPlace=Button(f, image=self.imgSearch, command=lambda x=self.billValues[count]:self.ctrlListPlace(x), padx=4, pady=1)
				myPlace.pack(side=RIGHT)
				self.balloon.bind(myCustomer, u"Séléctionner une Résidence")
			elif count == 5: # Date d'écheance
				Label(f, width=18, text=name, anchor=W).pack(side=LEFT)
				Entry(f, textvariable=self.billValues[count], width=21).pack(side=LEFT, fill=X)
				myCal2=Button(f, image=self.imgCalendar, command=lambda x=self.billValues[count]:self.ctrlCalendar(x), padx=4, pady=1)
				myCal2.pack(side=LEFT)
				self.balloon.bind(myCal2, u"Calendrier")
			elif count > 5 and count < 9:
				pass
			elif count == 9: # Notes
				Label(f, width=18, text=name, anchor=W).pack(side=LEFT)
				Entry(f, textvariable=self.billValues[count], width=21).pack(side=LEFT, fill=X)
				myNotes=Button(f, image=self.imgNotes, command=lambda x=self.billValues[count]:self.ctrlNotes(x,u"Notes"), padx=4, pady=1)
				myNotes.pack(side=RIGHT)
				self.balloon.bind(myNotes, u"Détails de la note")
			elif count == 10: # Status
				Label(f, width=18, text=name, anchor=W).pack(side=LEFT)
				self.billStatusCB=Pmw.ComboBox(f, selectioncommand=self.billStatus, scrolledlist_items=billStatusListCB, listheight=100)
				self.billStatusCB._entryfield._entryFieldEntry.config( width=21)
				self.billStatusCB.pack(side=LEFT, fill=X)
				self.billStatusCB.selectitem(0)
				self.billValues[count].set(u"E")
			elif count == 11: # StayBill séjour lié
				Label(f, width=18, text=name, anchor=W).pack(side=LEFT)
				Entry(f, textvariable=self.billValues[count], width=21, state=DISABLED, bd=0, disabledforeground="black").pack(side=LEFT, fill=X)
				self.billStayBillBt=Button(f, image=self.imgLinks, command=lambda x=self.billValues[count]:self.ctrlBillStay(x), padx=4, pady=1, state=DISABLED)
				self.balloon.bind(self.billStayBillBt, u"Séjours liées à cette pièce de vente.\nCommencer par créer une pièce de vente puis séléctionner le dans la\nliste pour pouvoir visualisé les Séjours liés.")
				self.billStayBillBt.pack(side=RIGHT)
			elif count == 12: # Paiements rattachés
				Label(f, width=18, text=name, anchor=W).pack(side=LEFT)
				Entry(f, textvariable=self.billValues[count], width=21, state=DISABLED, bd=0, disabledforeground="black").pack(side=LEFT, fill=X)
				self.billPaymentBillBt=Button(f, image=self.imgLinks, command=lambda x=self.billValues[count]:self.ctrlPaymentBill(x), padx=4, pady=1, state=DISABLED)
				self.balloon.bind(self.billPaymentBillBt, u"Paiements rattachés à cette pièce de vente.\nCommencer par créer une pièce de vente puis séléctionner le dans la\nliste pour pouvoir gérer les Paiements rattachés.")
				self.billPaymentBillBt.pack(side=RIGHT)
			elif count == 13: # Relances rattachée
				Label(f, width=18, text=name, anchor=W).pack(side=LEFT)
				Entry(f, textvariable=self.billValues[count], width=21, state=DISABLED, bd=0, disabledforeground="black").pack(side=LEFT, fill=X)
				self.billChasingUpBt=Button(f, image=self.imgLinks, command=lambda x=self.billValues[count]:self.ctrlChasingUp(x), padx=4, pady=1, state=DISABLED)
				self.balloon.bind(self.billChasingUpBt, u"Relances rattachées à cette pièce de vente.\nCommencer par créer une pièce de vente puis séléctionner le dans la\nliste pour pouvoir gérer les Relances rattachées.")
				self.billChasingUpBt.pack(side=RIGHT)
			else:
				Label(f, width=18, text=name, anchor=W).pack(side=LEFT)
				Entry(f, textvariable=self.billValues[count], width=23).pack(side=LEFT, fill=X)
			f.pack(side=TOP, fill=X)
			count += 1
		# Boutons enregistrement (new ou modify) et suppression
		s = Frame(leftFrame) 
		self.saveBillBt=Button(s, image=self.imgSave, command=self.createBill)
		self.saveBillBt.bind("<Return>", self.createBill)
		self.saveBillBt.pack(side=LEFT)
		self.balloon.bind(self.saveBillBt, u"Enregistrer")
		self.deleteBillBt=Button(s, image=self.imgDelete, command=self.deleteBill, state=DISABLED)
		self.deleteBillBt.bind("<Return>", self.deleteBill)
		self.deleteBillBt.pack(side=LEFT)
		self.balloon.bind(self.deleteBillBt, u"Supprimer")
		self.printBillBt=Button(s, image=self.imgPrint, command=self.printBill, state=DISABLED)
		self.printBillBt.bind("<Return>", self.printBill)
		self.printBillBt.pack(side=RIGHT, fill=X)
		self.balloon.bind(self.printBillBt, u"Imprimer(PDF)")
		s.pack(side=LEFT, fill=X)
		leftFrame.pack(side=LEFT, fill=X)
		# Liste des Bill existants (présentation colonne de droite)
		rightFrame = Frame(topFrame) 
		Label(rightFrame, text=u"Liste des Pièces de vente").pack(side=TOP, fill=X)
		self.searchBillValue = StringVar()
		self.searchBillEt = Entry(rightFrame,  width=83, textvariable=self.searchBillValue, relief=GROOVE)
		self.searchBillEt.bind("<KeyRelease>", self.searchBill)
		self.searchBillEt.pack(side=TOP, fill=X)
		self.balloon.bind(self.searchBillEt, u"Saisir les premières lettres d'une Référence de pièce\npour une recherche plus précise,\nla liste est classée par date.")
		s = Frame(rightFrame) 
		scrollbar = Scrollbar(s)
		scrollbar.pack(side=RIGHT, fill=Y)
		self.listBill = Listbox(s)
		self.listBill.config(yscrollcommand=scrollbar.set, width=80, selectmode=SINGLE, height=14)
		self.listBill.bind("<ButtonRelease-1>",self.selectBill)
		scrollbar.config(command=self.listBill.yview)
		self.listBill.pack()
		self.balloon.bind(self.listBill, u"Séléctionner une pièce de vente\npour la visualiser ou la modifier.")
		s.pack(side=TOP, fill=X)
		rightFrame.pack(side=RIGHT, fill=BOTH)
		topFrame.pack(side=TOP, fill=X)
		self.clearFieldBill()
		self.makeLineBill()
		# TODO ajouter un tableau avec les totaux par taxes
		footFrame = Frame(self)
		th=Frame(footFrame)
		Label(th, width=18, text=billLabels[6], anchor="w").pack(side=LEFT, fill=X)
		Entry(th, textvariable=self.billValues[6], width=10, justify=RIGHT, state=DISABLED, bd=0, disabledforeground="black").pack(side=LEFT)
		th.pack(side=TOP, fill=X)
		tt=Frame(footFrame)
		Label(tt, width=18, text=billLabels[7], anchor="w").pack(side=LEFT, fill=X)
		Entry(tt, textvariable=self.billValues[7], width=10, justify=RIGHT, state=DISABLED, bd=0, disabledforeground="black").pack(side=LEFT)
		tt.pack(side=TOP, fill=X)
		ttc=Frame(footFrame)
		Label(ttc, width=18, text=billLabels[8], font=self.numberFT, anchor="w").pack(side=LEFT, fill=X)
		Entry(ttc, textvariable=self.billValues[8], width=10, justify=RIGHT, state=DISABLED, bd=0, disabledforeground="black", font=self.numberFT ).pack(side=LEFT)
		ttc.pack(side=TOP, fill=X)
		footFrame.pack(side=RIGHT)
		# Initialisation
		self.searchBill()

	def billSort(self, value):
		sort = ((u"C", u"Commande"),(u"D", u"Devis"),(u"F", u"Facture"),(u"A", u"Avoir"),) 
		for n in sort:
			if n[1] == value: self.billValues[2].set(n[0])

	def billStatus(self, value):
		status = ((u"E", u"En cours"),(u"P", u"Payé"),(u"L", u"Litige"),(u"R", u"Remplacé"),(u"A", u"Annulé"),) 
		for n in status:
			if n[1] == value: self.billValues[10].set(n[0])

	def getDateTimeInBill(self):
		if self.billValues[0].get() != "":
			date=self.billValues[0].get().split("/")
			d = datetime.date(int(date[2]), int(date[1]), int(date[0]))
			return d
		else:
			return None

	def getDateTimeOutBill(self):
		if self.billValues[5].get() != "":
			date=self.billValues[5].get().split("/")
			d = datetime.date(int(date[2]), int(date[1]), int(date[0]))
			return d
		else:
			return None

	def verifyBill(self):
		if self.billValues[0].get() == "":
			showerror(u"Erreur de saisie", u"Le champ Date est obligatoire !\nMerci de le compléter.")
			return False
		elif self.billValues[1].get() == "":
			if askyesno(u"Erreur de saisie", u"Le champ Référence est obligatoire !\nSouhaitez-vous générer un numéro de piéce automatiquement ?."):
				n = self.getBillNumber()
				self.billValues[1].set(n)
			return False
		elif self.billValues[3].get() == "":
			showerror(u"Erreur de saisie", u"Le champ Client est obligatoire !\nMerci de le compléter.")
			return False
		elif self.billValues[4].get() == "": 
			showerror(u"Erreur de saisie", u"Le champ Résidence est obligatoire !\nMerci de le compléter.")
			return False
		else:
			return True

	def createBill(self, event=None):
		if self.verifyBill():
			if  self.deleteBillBt.config()["state"][4] == "normal":
				self.modifyBill()
			else:
				if askyesno(u"Enregistrement", u"Souhaitez-vous enregistrer une nouvelle Pièce référence %s  ?\n" % (self.billValues[1].get()) ):
					Bill(date=self.getDateTimeInBill(),
						reference=self.billValues[1].get().encode("utf-8"),
						sort=self.billValues[2].get().encode("utf-8"),
						customer=self.listObject[0],
						place=self.listObject[1],
						dueDate=self.getDateTimeOutBill(),
						tHTPrice=self.billValues[6].get().encode("utf-8"),
						tTaxPrice=self.billValues[7].get().encode("utf-8"),
						tTCPrice=self.billValues[8].get().encode("utf-8"),
						status=self.billValues[10].get().encode("utf-8"),
						notes=self.billValues[9].get().encode("utf-8"),
						createDate=datetime.datetime.now()
					)
					self.searchBill()
				self.clearFieldBill()

	def modifyBill(self, event=None): 
		if askyesno(u"Modifier", u"Souhaitez-vous modifier la Pièce référence %s ?" % self.selectedBill.reference):
			self.selectedBill.date=self.getDateTimeInBill()
			self.selectedBill.reference=self.billValues[1].get().encode("utf-8")
			self.selectedBill.sort=self.billValues[2].get().encode("utf-8")
			self.selectedBill.customer=self.listObject[0]
			self.selectedBill.place=self.listObject[1]
			self.selectedBill.dueDate=self.getDateTimeOutBill()
			self.selectedBill.tHTPrice=self.billValues[6].get().encode("utf-8")
			self.selectedBill.tTaxPrice=self.billValues[7].get().encode("utf-8")
			self.selectedBill.tTCPrice=self.billValues[8].get().encode("utf-8")
			self.selectedBill.status=self.billValues[10].get().encode("utf-8")
			self.selectedBill.notes=self.billValues[9].get().encode("utf-8")
			self.searchBill()
		self.deleteBillBt.config(state=DISABLED)
		# desactivation du bouton imprimer
		self.printBillBt.config(state=DISABLED)
		self.clearFieldBill()

	def deleteBill(self, event=None): 
		if askyesno(u"Suppression", u"Souhaitez-vous supprimer la Pièce référence %s ?\nCette opération est irréversible !" % self.selectedBill.reference):
			Bill.delete(self.selectedBill.id)
			self.searchBill()            
		self.deleteBillBt.config(state=DISABLED)
		# desactivation du bouton imprimer
		self.printBillBt.config(state=DISABLED)
		self.clearFieldBill()
		
	def printBill(self, event=None):
		if len(list(self.resultLineBill)) > 0:
			pdf=BillPDF(path=self.path, log=self.log, bill=self.selectedBill, lines=self.resultLineBill)
			if pdf.check == 1:
				showinfo(u"Success", u"Le fichier PDF est disponible dans le répertoire pdf")
			else:
				showerror(u"Erreur", u"Une erreur à empècher la création du fichier PDF !")
		else:
			showerror(u"Erreur", u"Impossible d'imprimer cette pièce\nil n'y a pas de lignes...!")
			
	# FIN de la gestion du module Bill ------------------------------------------------------------------------------------------------------------------------

	# DEBUT de la gestion du module LineBill -----------------------------------------------------------------------------------------------------------
	def clearFieldLineBill(self):
		# Mise a zéro des champs
		self.lineBillValues[0].set("")
		self.lineBillValues[1].set("")
		self.lineBillValues[2].set("")
		self.lineBillValues[3].set(u"0.00")
		self.lineBillValues[4].set(u"1.00")
		self.lineBillValues[5].set(u"0.00")
		self.lineBillValues[6].set("")
		self.lineBillValues[7].set(u"0.00")
		self.lineBillValues[8].set(u"FC")
		self.lineBillStatusCB.selectitem(2)
		# Taxe par défault
		result = Tax.select(Tax.q.id==self.defaultTaxID)
		for row in result:
			self.listObject[4]=row
		self.lineBillValues[6].set(row.rate)

	def selectLineBill(self, id=0):
		if id != 0:
			result = LineBill.select(LineBill.q.id==id)
			for row in result:
				self.selectedLineBill = row
			#~ self.listObject[2]=self.selectedLineBill.catalogue
			self.listObject[3]=self.selectedLineBill.reference
			self.listObject[4]=self.selectedLineBill.tax
			if self.selectedLineBill.reference != None:self.lineBillValues[1].set(self.selectedLineBill.reference.code)
			if self.selectedLineBill.tax != None:self.lineBillValues[6].set("%.2f" % self.selectedLineBill.tax.rate)
			if self.selectedLineBill.line != None:self.lineBillValues[0].set(self.selectedLineBill.line)
			if self.selectedLineBill.designation != None:self.lineBillValues[2].set(self.selectedLineBill.designation)                
			if self.selectedLineBill.price != None:self.lineBillValues[3].set("%.2f" % self.selectedLineBill.price)
			if self.selectedLineBill.quantity != None:self.lineBillValues[4].set("%.2f" % self.selectedLineBill.quantity)
			if self.selectedLineBill.totalPrice != None:self.lineBillValues[5].set("%.2f" % self.selectedLineBill.totalPrice)
			if self.selectedLineBill.priceInclusTax != None:self.lineBillValues[7].set("%.2f" % self.selectedLineBill.priceInclusTax)                
			# Affichage du Status dans la ComboBox
			status = ((u"FO", 0),(u"FR", 1),(u"FC", 2),(u"CC", 3),(u"CR", 4),(u"CL", 5),(u"A", 6),)
			for n in status:
				if n[0] == self.selectedLineBill.status: self.lineBillStatusCB.selectitem(n[1])
			# activation du bouton supprimer
			self.deleteLineBillBt.config(state=NORMAL)

	def searchLineBill(self, event=None):
		if self.listLineBill is not None:self.listLineBill.destroy()
		self.listLineBill=Frame(self.listFrame.interior())
		self.clearFieldLineBill()
		self.valuesTHTLineBill = []
		self.valuesTTCBill = []
		self.resultLineBill = LineBill.select(LineBill.q.bill==self.listObject[2],orderBy=LineBill.q.line)
		lineValues = [StringVar(),StringVar(),StringVar(),StringVar(),StringVar(),StringVar(),StringVar(),StringVar(),StringVar()]
		count=0
		for row in self.resultLineBill:
			t = Frame(self.listLineBill)
			lineValues[0].set(str(row.line)) # Line number
			lineValues[1].set(row.reference.code) # Reference
			lineValues[2].set(row.designation) # Designation
			lineValues[3].set("%.2f" % row.price) # Price UHT
			lineValues[4].set("%.2f" % row.quantity) # Quantity
			lineValues[5].set("%.2f" % row.totalPrice) # Price THT
			lineValues[6].set("%.2f" % row.tax.rate) # Tax
			lineValues[7].set("%.2f" % row.priceInclusTax) # Price TTC
			lineValues[8].set(row.status) # Status
			Entry(t, textvariable= lineValues[0], width=2, justify=CENTER, state=DISABLED, bd=0, disabledforeground="black", disabledbackground="white").pack(side=LEFT)
			Entry(t, textvariable= lineValues[1], width=23, justify=CENTER, state=DISABLED, bd=0, disabledforeground="black", disabledbackground="white").pack(side=LEFT)
			Entry(t, textvariable= lineValues[2], width=24, state=DISABLED, bd=0, disabledforeground="black", disabledbackground="white").pack(side=LEFT)
			Entry(t, textvariable= lineValues[3], width=10, justify=RIGHT, state=DISABLED, bd=0, disabledforeground="black", disabledbackground="white").pack(side=LEFT)
			Entry(t, textvariable= lineValues[4], width=9, justify=RIGHT, state=DISABLED, bd=0, disabledforeground="black", disabledbackground="white").pack(side=LEFT)
			Entry(t, textvariable= lineValues[5], width=11, justify=RIGHT, state=DISABLED, bd=0, disabledforeground="black", disabledbackground="white").pack(side=LEFT)
			Entry(t, textvariable= lineValues[6], width=8, justify=RIGHT, state=DISABLED, bd=0, disabledforeground="black", disabledbackground="white").pack(side=LEFT)
			Entry(t, textvariable= lineValues[7], width=11, justify=RIGHT, state=DISABLED, bd=0, disabledforeground="black", disabledbackground="white").pack(side=LEFT)
			Entry(t, textvariable= lineValues[8], width=15, justify=CENTER, state=DISABLED, bd=0, disabledforeground="black", disabledbackground="white").pack(side=LEFT)
			myID=Button(t, image=self.imgSearch, command=lambda x=row.id:self.selectLineBill(x), padx=4, pady=1)
			myID.pack(side=RIGHT)
			self.balloon.bind(myID, u"Modifier ou supprimer cette ligne")
			t.pack(side=TOP, fill=X)
			lineValues = [StringVar(),StringVar(),StringVar(),StringVar(),StringVar(),StringVar(),StringVar(),StringVar(),StringVar()]
			self.valuesTHTLineBill.append(row.totalPrice)
			self.valuesTTCBill.append(row.priceInclusTax)
			count+=1
		self.listLineBill.pack(side=TOP, fill=X)
		self.lineBillValues[0].set(str(count+1))
		self.calculateListLinesBill()

	def makeLineBill(self):
		bottomFrame = Frame(self)
		leftLCFrame = Frame(bottomFrame, relief=SUNKEN, borderwidth=1)
		lineBillLabels = (u"N°", u"Références", u"Désignation", u"Prix UHT", u"Quantité", u"Prix THT", u"Taxe", u"Prix TTC", u"Etat")
		self.lineBillValues = [StringVar(),StringVar(),StringVar(),StringVar(),StringVar(),StringVar(),StringVar(),StringVar(),StringVar()]
		lineBillStatusListCB = (u"Option", u"Réservé", u"Consommé", u"Commandé", u"Reliquat", u"Livré", u"Annulé")
		count = 0
		p = Frame(leftLCFrame)
		for name in lineBillLabels:
			f = Frame(p)            
			if count == 0: # Numéro de la ligne
				Label(f, width=2, text=name).pack(side=TOP)
				Entry(f, textvariable=self.lineBillValues[count], width=2, justify=RIGHT).pack(side=TOP)
			elif count == 1: # Référence
				Label(f, width=22, text=name).pack(side=TOP)
				t= Frame(f)
				Entry(t, textvariable=self.lineBillValues[count], width=20, state=DISABLED, bd=0, disabledforeground="black").pack(side=LEFT, fill=X)
				myReference=Button(t, image=self.imgSearch, command=lambda x=self.lineBillValues[count]:self.ctrlListReference(x), padx=4, pady=1)
				myReference.pack(side=RIGHT)
				self.balloon.bind(myReference, u"Séléctionner une Référence")
				t.pack(side=TOP)
			elif count == 2: # Désignation
				Label(f, width=22, text=name).pack(side=TOP)
				t= Frame(f)
				Entry(t, textvariable=self.lineBillValues[count], width=20).pack(side=LEFT)
				myDesignation=Button(t, image=self.imgNotes, command=lambda x=self.lineBillValues[count]:self.ctrlNotes(x,u"Désignation"), padx=4, pady=1)
				myDesignation.pack(side=LEFT)
				self.balloon.bind(myDesignation, u"Détails de la Désignation")
				t.pack(side=TOP)
			elif count == 3: # Pris unitaire HT
				Label(f, width=9, text=name).pack(side=TOP)
				t= Frame(f)
				phtEt=Entry(t, textvariable=self.lineBillValues[count], width=7, justify=RIGHT)
				phtEt.pack(side=LEFT)
				phtEt.bind("<Return>", self.calculateLineBill)
				myCalculate1=Button(t, image=self.imgCalculate, command=self.calculateLineBill, padx=4, pady=1)
				myCalculate1.pack(side=RIGHT)
				self.balloon.bind(myCalculate1, u"Calculer la ligne")
				t.pack(side=TOP)
			elif count == 4: # Quantité
				Label(f, width=9, text=name).pack(side=TOP)
				t= Frame(f)
				qtEt=Entry(t, textvariable=self.lineBillValues[count], width=6, justify=RIGHT)
				qtEt.pack(side=LEFT)
				qtEt.bind("<Return>", self.calculateLineBill)
				myCalculate2=Button(t, image=self.imgCalculate, command=self.calculateLineBill, padx=4, pady=1)
				myCalculate2.pack(side=RIGHT)
				self.balloon.bind(myCalculate2, u"Calculer la ligne")
				t.pack(side=TOP)
			elif count == 5: # Prix THT
				Label(f, width=10, text=name).pack(side=TOP)
				Entry(f, textvariable=self.lineBillValues[count], width=10, justify=RIGHT, state=DISABLED, bd=0, disabledforeground="black").pack(side=TOP)
			elif count == 6: # Tax
				Label(f, width=9, text=name).pack(side=TOP)
				t= Frame(f)
				Entry(t, textvariable=self.lineBillValues[count], width=5, justify=RIGHT, state=DISABLED, bd=0, disabledforeground="black").pack(side=LEFT, fill=X)
				myTax=Button(t, image=self.imgSearch, command=lambda x=self.lineBillValues[count]:self.ctrlListTax(x), padx=4, pady=1)
				myTax.pack(side=RIGHT)
				self.balloon.bind(myTax, u"Séléctionner une Taxe")
				t.pack(side=TOP)
			elif count == 7: # Prix TTC
				Label(f, width=10, text=name).pack(side=TOP)
				Entry(f, textvariable=self.lineBillValues[count], width=10, justify=RIGHT, state=DISABLED, bd=0, disabledforeground="black").pack(side=TOP)
			elif count == 8: # Status
				Label(f, width=12, text=name).pack(side=TOP)
				self.lineBillStatusCB=Pmw.ComboBox(f, selectioncommand=self.lineBillStatus, scrolledlist_items=lineBillStatusListCB, listheight=140)
				self.lineBillStatusCB._entryfield._entryFieldEntry.config( width=12)
				self.lineBillStatusCB.pack(side=TOP)
				self.lineBillStatusCB.selectitem(2)
				self.lineBillValues[count].set(u"FC")
			else: 
				pass
			f.pack(side=LEFT)
			count += 1
		f = Frame(p)
		# Boutons enregistrement (new ou modify) et suppression
		self.saveLineBillBt=Button(f, image=self.imgSave, command=self.createLineBill)
		self.saveLineBillBt.bind("<Return>", self.createLineBill)
		self.saveLineBillBt.pack(side=LEFT)
		self.balloon.bind(self.saveLineBillBt, u"Enregistrer")
		self.deleteLineBillBt=Button(f, image=self.imgDelete, command=self.deleteLineBill, state=DISABLED)
		self.deleteLineBillBt.bind("<Return>", self.deleteLineBill)
		self.deleteLineBillBt.pack(side=LEFT)
		self.balloon.bind(self.deleteLineBillBt, u"Supprimer")
		f.pack(side=LEFT)
		p.pack(side=TOP, fill=X)
		self.listFrame= Pmw.ScrolledFrame(leftLCFrame, usehullsize = 1, hull_height = 160)
		self.listLineBill=None
		self.listFrame.pack(side=TOP, fill=BOTH)
		leftLCFrame.pack(side=LEFT, fill=X)
		bottomFrame.pack(side=TOP, fill=X)
		self.clearFieldLineBill()

	def ctrlCalendar(self,field):
		CalendarGUI(field=field, log=self.log, path=self.path)

	def ctrlNotes(self,field,title):
		NotesGUI(field=field,title=title, log=self.log, path=self.path)

	def ctrlListReference(self,field): # index 3
		ReferenceListGUI(balloon=self.balloon, field=field, index=3, listObject=self.listObject, log=self.log, path=self.path)

	def ctrlListTax(self,field): # index 4
		TaxListGUI(balloon=self.balloon, field=field, index=4, listObject=self.listObject, log=self.log, path=self.path)

	def ctrlListPlace(self,field): # index 1
		PlaceListGUI(balloon=self.balloon, field=field, index=1, listObject=self.listObject, log=self.log, path=self.path)

	def ctrlListPerson(self,field): # index 0
		PersonListGUI(balloon=self.balloon, field=field, index=0, listObject=self.listObject, log=self.log, path=self.path)

	def ctrlBillStay(self,field): # index 2
		BillStayGUI(balloon=self.balloon, field=field, index=2, listObject=self.listObject, log=self.log, path=self.path)

	def ctrlPaymentBill(self,field): # index 2
		PaymentBillGUI(balloon=self.balloon, field=field, index=2, listObject=self.listObject, log=self.log, path=self.path)

	def ctrlChasingUp(self,field): # index 2
		ChasingUpGUI(balloon=self.balloon, field=field, index=2, listObject=self.listObject, log=self.log, path=self.path)

	def lineBillStatus(self, value): 
		status = ((u"FO", u"Option"),(u"FR", u"Réservé"),(u"FC", u"Consommé"),(u"CC", u"Commandé"),(u"CR", u"Reliquat"),(u"CL", u"Livré"),(u"A", u"Annulé"),) 
		for n in status:
			if n[1] == value: self.lineBillValues[8].set(n[0])

	def calculateLineBill(self, event=None):
		pht = float(self.lineBillValues[3].get())
		qt = float(self.lineBillValues[4].get())
		tax = float(self.lineBillValues[6].get())
		ptht = round(pht*qt,2)
		ptttc = round(ptht + (ptht*(tax/100)),2)
		self.lineBillValues[5].set("%.2f" % ptht)
		self.lineBillValues[7].set("%.2f" % ptttc)

	def calculateListLinesBill(self):
		if len(self.valuesTHTLineBill) != 0:
			sumTHT = float(0.0)
			sumTTC = float(0.0)
			for value in self.valuesTHTLineBill:
				sumTHT+=float(value)
			for value in self.valuesTTCBill:
				sumTTC+=float(value)
			sumTax = sumTTC - sumTHT
			if self.billValues[6] !=  sumTHT:
				self.billValues[6].set("%.2f" % sumTHT)
				self.selectedBill.tHTPrice=self.billValues[6].get().encode("utf-8")
			if self.billValues[7] !=  sumTax:
				self.billValues[7].set("%.2f" % sumTax)
				self.selectedBill.tTaxPrice=self.billValues[7].get().encode("utf-8")
			if self.billValues[8] !=  sumTTC:
				self.billValues[8].set("%.2f" % sumTTC)
				self.selectedBill.tTCPrice=self.billValues[8].get().encode("utf-8")

	def verifyLineBill(self):
		if self.lineBillValues[0].get() == "":
			showerror(u"Erreur de saisie", u"Le champ N° de ligne est obligatoire !\nMerci de le compléter.")
			return False
		elif self.lineBillValues[2].get() == "":
			showerror(u"Erreur de saisie", u"Le champ Désignation est obligatoire !\nMerci de le compléter.")
			return False
		elif self.lineBillValues[3].get() == "":
			showerror(u"Erreur de saisie", u"Le champ Prix UHT est obligatoire !\nMerci de le compléter.")
			return False
		elif self.lineBillValues[4].get() == "":
			showerror(u"Erreur de saisie", u"Le champ Quantité est obligatoire !\nMerci de le compléter.")
			return False
		elif self.lineBillValues[6].get() == "":
			showerror(u"Erreur de saisie", u"Le champ Taxe est obligatoire !\nMerci de le compléter.")
			return False            
		else:
			return True

	def createLineBill(self, event=None):
		if self.verifyLineBill():
			if  self.deleteLineBillBt.config()["state"][4] == "normal":
				self.modifyLineBill()
			else:
				if askyesno(u"Enregistrement", u"Souhaitez-vous enregistrer la ligne %s comme une nouvelle ligne de la pièce de vente en cours ?\n" % self.lineBillValues[0].get()):
					LineBill(bill=self.listObject[2],
						line=int(self.lineBillValues[0].get()),
						reference=self.listObject[3],
						designation=self.lineBillValues[2].get().encode("utf-8"),
						price=self.lineBillValues[3].get().encode("utf-8"),
						quantity=self.lineBillValues[4].get().encode("utf-8"),
						totalPrice=self.lineBillValues[5].get().encode("utf-8"),
						tax=self.listObject[4],
						priceInclusTax=self.lineBillValues[7].get().encode("utf-8"),
						status=self.lineBillValues[8].get().encode("utf-8"),
						createDate=datetime.datetime.now()
					)
				self.clearFieldLineBill()
				self.searchLineBill()

	def modifyLineBill(self, event=None): 
		if askyesno(u"Modifier", u"Souhaitez-vous modifier la ligne %s de la pièce de vente en cours ?" % self.selectedLineBill.line):
			self.selectedLineBill.line=int(self.lineBillValues[0].get())
			self.selectedLineBill.reference=self.listObject[3]
			self.selectedLineBill.designation=self.lineBillValues[2].get().encode("utf-8")
			self.selectedLineBill.price=self.lineBillValues[3].get().encode("utf-8")
			self.selectedLineBill.quantity=self.lineBillValues[4].get().encode("utf-8")
			self.selectedLineBill.totalPrice=self.lineBillValues[5].get().encode("utf-8")
			self.selectedLineBill.tax=self.listObject[4]
			self.selectedLineBill.priceInclusTax=self.lineBillValues[7].get().encode("utf-8")
			self.selectedLineBill.status=self.lineBillValues[8].get().encode("utf-8")
		self.deleteLineBillBt.config(state=DISABLED)
		self.clearFieldLineBill()
		self.searchLineBill()

	def deleteLineBill(self, event=None): 
		if askyesno(u"Suppression", u"Souhaitez-vous supprimer la ligne %s de la pièce de vente en cours ?\nCette opération est irréversible !" % self.selectedLineBill.line):
			LineBill.delete(self.selectedLineBill.id)
		self.deleteLineBillBt.config(state=DISABLED)
		self.clearFieldLineBill()
		self.searchLineBill()
	# FIN de la gestion du module LineBill --------------------------------------------------------------------------------------------------------------

class BillListGUI(Toplevel):
	def __init__(self, parent=None, balloon=None, field=None, index=None, listObject=None, path=None, log=None):
		Toplevel.__init__(self, parent)
		self.parent=parent
		self.grab_set() 
		self.transient(self.master)
		self.resizable(width=False, height=False)
		self.title(u"Liste des Pièces")
		self.balloon=balloon
		self.imgNew=PhotoImage(file="img/add_alternative_icon.gif")
		self.field=field
		self.index=index
		self.listObject=listObject
		self.path=path
		self.log=log
		# Afficher un icon personnalisé
		try:
			if os.name =="posix":
				img = PhotoImage(file=self.path+"/icons/Bill-icon.gif")
				self.tk.call("wm", "iconphoto", self._w, img)
			else:
				self.iconbitmap(default=self.path+"/icons/Bill-icon.gif")
		except TclError:
			self.log.warning("Le window manager ne supporte pas la jolie icône que je veux lui mettre... tant pis")
		self.log.info("\tBillListGUI\tStart")
		self.makeListBill()

	def selectListBill(self, event):
		if self.listListBill.get(0)!="":
			result = Bill.select(Bill.q.id==self.idListListBill[int(self.listListBill.curselection()[0])])
			for row in result:
				self.listObject[self.index]=row
				self.field.set(row.reference+" - "+row.customer.lname)
				self.destroy()

	def searchListBill(self, event=None):
		if self.searchListBillValue.get() != "":
			self.listListBill.delete(0,END)
			self.idListListBill = []
			result = Bill.select(Bill.q.reference.startswith(self.searchListBillValue.get().encode("utf-8")), orderBy=Bill.q.date)
			for row in result:
				self.listListBill.insert(END, row.reference+" - "+row.customer.lname)
				self.idListListBill.append(row.id)
		else:
			self.listListBill.delete(0,END)
			self.idListListBill = []
			result = Bill.select(orderBy=Bill.q.date)
			for row in result:
				self.listListBill.insert(END, row.reference+" - "+row.customer.lname)
				self.idListListBill.append(row.id)

	def makeListBill(self):
		leftFrame = Frame(self)
		Label(leftFrame, text=u"Liste des Pièces").pack(side=TOP, fill=X)
		self.searchListBillValue = StringVar()
		s = Frame(leftFrame) 
		self.searchListBillEt = Entry(s,  width=42, textvariable=self.searchListBillValue, relief=GROOVE)
		self.searchListBillEt.bind("<KeyRelease>", self.searchListBill)
		self.searchListBillEt.pack(side=LEFT, fill=X)
		self.balloon.bind(self.searchListBillEt, u"Saisir les premiéres lettres d'une référence de pièce\npour une recherche plus précise,\nla liste est classée par Date.")
		newBillBt=Button(s, image=self.imgNew, command=self.ctrlBill)
		newBillBt.pack(side=RIGHT)
		self.balloon.bind(newBillBt, u"Créer une nouvelle Pièce de vente")
		s.pack(side=TOP, fill=X)
		s = Frame(leftFrame) 
		scrollbar = Scrollbar(s)
		scrollbar.pack(side=RIGHT, fill=Y)
		self.listListBill = Listbox(s)
		self.listListBill.config(yscrollcommand=scrollbar.set,width=43, selectmode=SINGLE, height=16)
		self.listListBill.bind("<ButtonRelease-1>",self.selectListBill)
		scrollbar.config(command=self.listListBill.yview)
		self.listListBill.pack()
		self.balloon.bind(self.listListBill, u"Séléctionner une Pièces.")
		s.pack(side=TOP, fill=X)
		leftFrame.pack()
		self.searchListBill()

	def ctrlBill(self):
		BillGUI(balloon=self.balloon, log=self.log, path=self.path)

class PaymentBillGUI(Toplevel):
	def __init__(self, parent=None, balloon=None, field=None, index=None, listObject=None, path=None, log=None):
		Toplevel.__init__(self, parent)
		self.parent=parent
		self.grab_set() 
		self.transient(self.master)
		self.resizable(width=False, height=False)
		self.title(u"Paiement(s) liée au Séjour")
		self.balloon=balloon
		self.imgSave=PhotoImage(file="img/save_icon.gif")
		self.imgDelete=PhotoImage(file="img/delete_icon.gif")
		self.imgCalendar=PhotoImage(file="img/calendar.gif")
		self.field=field
		self.index=index
		self.listObject=listObject
		self.path=path
		self.log=log
		# Afficher un icon personnalisé
		try:
			if os.name =="posix":
				img = PhotoImage(file=self.path+"/icons/Bill-icon.gif")
				self.tk.call("wm", "iconphoto", self._w, img)
			else:
				self.iconbitmap(default=self.path+"/icons/Bill-icon.gif")
		except TclError:
			self.log.warning("Le window manager ne supporte pas la jolie icône que je veux lui mettre...")
		self.log.info("\tPaymentBillGUI\tStart")
		self.makePaymentBill()

	# DEBUT de la gestion du module PaymentBill --------------------------------------------------------------------------------------------
	def clearFieldPaymentBill(self):
		# Mise a zéro des champs
		self.paymentBillValues[0].set("")
		self.paymentBillValues[1].set("")
		self.paymentBillValues[2].set(u"R")
		self.paymentBillValues[3].set(u"0.00")
		self.paymentBillValues[4].set(u"CB")
		self.paymentBillValues[5].set(u"RB")
		self.paymentBillStatusCB.selectitem(2)
		self.paymentBillModeCB.selectitem(2)
		self.paymentBillDesignationCB.selectitem(1)
		# Affichage de la présence de Paiements lié a ce séjour
		result = PaymentBill.select(PaymentBill.q.bill==self.listObject[self.index])
		count=0
		for row in result:
			count+=1            
		if count < 2:
			self.field.set(str(count)+u" Paiement")
		else:
			self.field.set(str(count)+u" Paiements")

	def selectPaymentBill(self, event=None):
		if self.listPaymentBill.get(0)!="":
			result = PaymentBill.select(PaymentBill.q.id==self.idListPaymentBill[int(self.listPaymentBill.curselection()[0])])
			for row in result:
				self.selectedPaymentBill = row
			#~ self.listObject[2]=self.selectedPaymentBill.bill
			if self.selectedPaymentBill.line != None:self.paymentBillValues[0].set(self.selectedPaymentBill.line)
			if self.selectedPaymentBill.date != None:self.paymentBillValues[1].set(self.selectedPaymentBill.date.strftime("%d/%m/%Y"))
			if self.selectedPaymentBill.designation != None:self.paymentBillValues[2].set(self.selectedPaymentBill.designation)
			if self.selectedPaymentBill.price != None:self.paymentBillValues[3].set(self.selectedPaymentBill.price)
			if self.selectedPaymentBill.mode != None:self.paymentBillValues[4].set(self.selectedPaymentBill.mode)                
			if self.selectedPaymentBill.status != None:self.paymentBillValues[5].set(self.selectedPaymentBill.status)             
			# Affichage du Status dans la ComboBox
			status = ((u"EA", 0),(u"RE", 1),(u"RB", 2),(u"EN", 3),(u"LI", 4),(u"BL", 5),)
			for n in status:
				if n[0] == self.selectedPaymentBill.status: self.paymentBillStatusCB.selectitem(n[1])
			# Affichage du Mode dans la ComboBox
			mode = ((u"ES", 0),(u"CH", 1),(u"CB", 2),(u"AM", 3),(u"TR", 4),(u"PV", 5),)
			for n in mode:
				if n[0] == self.selectedPaymentBill.mode: self.paymentBillModeCB.selectitem(n[1])
			# Affichage du Designation dans la ComboBox
			designation = ((u"A", 0),(u"R", 1),(u"T", 2),(u"V", 3),(u"E", 4),)
			for n in designation:
				if n[0] == self.selectedPaymentBill.designation: self.paymentBillDesignationCB.selectitem(n[1])                    
			# activation du bouton supprimer
			self.deletePaymentBillBt.config(state=NORMAL)

	def searchPaymentBill(self, event=None):
		self.listPaymentBill.delete(0,END)
		self.idListPaymentBill = []
		result = PaymentBill.select(PaymentBill.q.bill==self.listObject[self.index],orderBy=PaymentBill.q.line)
		count=0
		for row in result:
			self.listPaymentBill.insert(END, str(row.line)+" - "+row.date.strftime("%d/%m/%Y")+" - "+row.designation+" - "+str(row.price)+" - "+row.mode+" - "+row.status)
			self.idListPaymentBill.append(row.id)
			count+=1
		self.paymentBillValues[0].set(str(count+1))

	def makePaymentBill(self):
		leftLCFrame = Frame(self)
		Label(leftLCFrame, text=u"Paiements").pack(side=TOP, fill=X)
		paymentBillLabels = (u"N°", u"Date", u"Désignation", u"Montant", u"Mode", u"Etat")
		self.paymentBillValues = [StringVar(),StringVar(),StringVar(),StringVar(),StringVar(),StringVar()]
		paymentBillStatusListCB = (u"En attente", u"Reçu", u"Remis en banque", u"Encaissé", u"Litige", u"Bloqué")
		paymentBillModeListCB = (u"Espèces", u"Chèque", u"CB", u"AMEX", u"Traite", u"Prélèvement")
		paymentBillDesignationListCB = (u"Accompte", u"Réglement", u"Traite", u"Avoir", u"Remboursement")
		count = 0
		for name in paymentBillLabels:
			f = Frame(leftLCFrame)
			Label(f, width=12, text=name, anchor=W).pack(side=LEFT)
			if count == 1: # Date
				Entry(f, textvariable=self.paymentBillValues[count], width=21).pack(side=LEFT, fill=X)
				myCal1=Button(f, image=self.imgCalendar, command=lambda x=self.paymentBillValues[count]:self.ctrlCalendar(x), padx=4, pady=1)
				myCal1.pack(side=LEFT) 
				self.balloon.bind(myCal1, u"Calendrier")
			elif count == 2: # Designation
				self.paymentBillDesignationCB=Pmw.ComboBox(f, selectioncommand=self.paymentBillDesignation, scrolledlist_items=paymentBillDesignationListCB, listheight=140)
				self.paymentBillDesignationCB._entryfield._entryFieldEntry.config( width=21)
				self.paymentBillDesignationCB.pack(side=LEFT, fill=X)
				self.paymentBillDesignationCB.selectitem(1)
				self.paymentBillValues[count].set(u"R")
			elif count == 3: # Montant
				phtEt=Entry(f, textvariable=self.paymentBillValues[count], width=24, justify=RIGHT)
				phtEt.pack(side=LEFT, fill=X)
			elif count == 4: # Mode
				self.paymentBillModeCB=Pmw.ComboBox(f, selectioncommand=self.paymentBillMode, scrolledlist_items=paymentBillModeListCB, listheight=140)
				self.paymentBillModeCB._entryfield._entryFieldEntry.config( width=21)
				self.paymentBillModeCB.pack(side=LEFT, fill=X)
				self.paymentBillModeCB.selectitem(2)
				self.paymentBillValues[count].set(u"CB")
			elif count == 5: # Status
				self.paymentBillStatusCB=Pmw.ComboBox(f, selectioncommand=self.paymentBillStatus, scrolledlist_items=paymentBillStatusListCB, listheight=140)
				self.paymentBillStatusCB._entryfield._entryFieldEntry.config( width=21)
				self.paymentBillStatusCB.pack(side=LEFT, fill=X)
				self.paymentBillStatusCB.selectitem(2)
				self.paymentBillValues[count].set(u"RB")
			else: 
				Entry(f, textvariable=self.paymentBillValues[count], width=23).pack(side=LEFT, fill=X)
			f.pack(side=TOP, fill=X)
			count += 1
		# Boutons enregistrement (new ou modify) et suppression
		s = Frame(leftLCFrame) 
		self.savePaymentBillBt=Button(s, image=self.imgSave, command=self.createPaymentBill)
		self.savePaymentBillBt.bind("<Return>", self.createPaymentBill)
		self.savePaymentBillBt.pack(side=LEFT)
		self.balloon.bind(self.savePaymentBillBt, u"Enregistrer")
		self.deletePaymentBillBt=Button(s, image=self.imgDelete, command=self.deletePaymentBill, state=DISABLED)
		self.deletePaymentBillBt.bind("<Return>", self.deletePaymentBill)
		self.deletePaymentBillBt.pack(side=LEFT)
		self.balloon.bind(self.deletePaymentBillBt, u"Supprimer")
		s.pack(side=TOP, fill=X)
		leftLCFrame.pack(side=LEFT, fill=X)
		# Liste des Lignes d'une pièce (présentation colonne de droite)
		rightLCFrame = Frame(self) 
		Label(rightLCFrame, text=u"Liste des Paiements").pack(side=TOP, fill=X)
		s = Frame(rightLCFrame) 
		scrollbar = Scrollbar(s)
		scrollbar.pack(side=RIGHT, fill=Y)
		self.listPaymentBill = Listbox(s)
		self.listPaymentBill.config(yscrollcommand=scrollbar.set, width=50, selectmode=SINGLE, height=9)
		self.listPaymentBill.bind("<ButtonRelease-1>",self.selectPaymentBill)
		scrollbar.config(command=self.listPaymentBill.yview)
		self.listPaymentBill.pack()
		self.balloon.bind(self.listPaymentBill, u"Séléctionner une lignes\npour le visualiser ou la modifier.")
		s.pack(side=TOP, fill=X)
		rightLCFrame.pack(side=RIGHT, fill=X)
		self.clearFieldPaymentBill()
		self.searchPaymentBill()

	def ctrlCalendar(self,field):
		CalendarGUI(field=field, log=self.log, path=self.path)

	def paymentBillDesignation(self, value):
		designation = ((u"A", u"Accompte"),(u"R", u"Réglement"),(u"T", u"Traite"),(u"V", u"Avoir"),(u"E", u"Remboursement"),)
		for n in designation:
			if n[1] == value: self.paymentBillValues[2].set(n[0])

	def paymentBillMode(self, value):
		mode = ((u"ES", u"Espèces"),(u"CH", u"Chèque"),(u"CB", u"CB"),(u"AM", u"AMEX"),(u"TR", u"Traite"),(u"PV", u"Prélèvement"),)
		for n in mode:
			if n[1] == value: self.paymentBillValues[4].set(n[0])

	def paymentBillStatus(self, value):
		status = ((u"EA", u"En attente"),(u"RE", u"Reçu"),(u"RB", u"Remis en banque"),(u"EN", u"Encaissé"),(u"LI", u"Litige"),(u"BL", u"Bloqué"),)
		for n in status:
			if n[1] == value: self.paymentBillValues[5].set(n[0])

	def getDatePaymentBill(self):
		if self.paymentBillValues[1].get() != "":
			dt= self.paymentBillValues[1].get().split("/")
			d = datetime.date(int(dt[2]), int(dt[1]), int(dt[0]))
			return d
		else:
			return None

	def verifyPaymentBill(self):
		if self.paymentBillValues[0].get() == "":
			showerror(u"Erreur de saisie", u"Le champ N° de ligne est obligatoire !\nMerci de le compléter.")
			return False
		elif self.paymentBillValues[1].get() == "":
			showerror(u"Erreur de saisie", u"Le champ Date est obligatoire !\nMerci de le compléter.")
			return False
		elif self.paymentBillValues[4].get() == "":
			showerror(u"Erreur de saisie", u"Le champ Montant est obligatoire !\nMerci de le compléter.")
			return False          
		else:
			return True

	def createPaymentBill(self, event=None):
		if self.verifyPaymentBill():
			if  self.deletePaymentBillBt.config()["state"][4] == "normal":
				self.modifyPaymentBill()
			else:
				if askyesno(u"Enregistrement", u"Souhaitez-vous enregistrer la ligne %s comme un nouveau paiement pour la pièce de vente en cours ?\n" % self.paymentBillValues[0].get()):
					PaymentBill(bill=self.listObject[self.index],
						line=int(self.paymentBillValues[0].get()),
						date=self.getDatePaymentBill(),
						designation=self.paymentBillValues[2].get().encode("utf-8"),
						price=self.paymentBillValues[3].get().encode("utf-8"),
						mode=self.paymentBillValues[4].get().encode("utf-8"),
						status=self.paymentBillValues[5].get().encode("utf-8"),
						createDate=datetime.datetime.now()
					)
				self.clearFieldPaymentBill()
				self.searchPaymentBill()

	def modifyPaymentBill(self, event=None): 
		if askyesno(u"Modifier", u"Souhaitez-vous modifier la ligne %s paiement de la pièce de vente en cours ?" % self.selectedPaymentBill.line):
			self.selectedPaymentBill.line=int(self.paymentBillValues[0].get())
			self.selectedPaymentBill.date=self.getDatePaymentBill()
			self.selectedPaymentBill.designation=self.paymentBillValues[2].get().encode("utf-8")
			self.selectedPaymentBill.price=self.paymentBillValues[3].get().encode("utf-8")
			self.selectedPaymentBill.mode=self.paymentBillValues[4].get().encode("utf-8")
			self.selectedPaymentBill.status=self.paymentBillValues[5].get().encode("utf-8")
		self.deletePaymentBillBt.config(state=DISABLED)
		self.clearFieldPaymentBill()
		self.searchPaymentBill()

	def deletePaymentBill(self, event=None): 
		if askyesno(u"Suppression", u"Souhaitez-vous supprimer la ligne %s paiement de la pièce de vente en cours ?\nCette opération est irréversible !" % self.selectedPaymentBill.line):
			PaymentBill.delete(self.selectedPaymentBill.id)
		self.deletePaymentBillBt.config(state=DISABLED)
		self.clearFieldPaymentBill()
		self.searchPaymentBill()
	# FIN de la gestion du module PaymentBill --------------------------------------------------------------------------------------------------------

class ChasingUpGUI(Toplevel):
	def __init__(self, parent=None, balloon=None, field=None, index=None, listObject=None, path=None, log=None):
		Toplevel.__init__(self, parent)
		self.parent=parent
		self.grab_set() 
		self.transient(self.master)
		self.resizable(width=False, height=False)
		self.title(u"Relance(s) liée au Séjour")
		self.balloon=balloon
		self.imgSave=PhotoImage(file="img/save_icon.gif")
		self.imgDelete=PhotoImage(file="img/delete_icon.gif")
		self.imgCalendar=PhotoImage(file="img/calendar.gif")
		self.imgNotes=PhotoImage(file="img/edit.gif")
		self.field=field
		self.index=index
		self.listObject=listObject
		self.path=path
		self.log=log
		# Afficher un icon personnalisé
		try:
			if os.name =="posix":
				img = PhotoImage(file=self.path+"/icons/Bill-icon.gif")
				self.tk.call("wm", "iconphoto", self._w, img)
			else:
				self.iconbitmap(default=self.path+"/icons/Bill-icon.gif")
		except TclError:
			self.log.warning("Le window manager ne supporte pas la jolie icône que je veux lui mettre...")
		self.log.info("\tChasingUpGUI\tStart")
		self.makeChasingUp()

	# DEBUT de la gestion du module ChasingUp --------------------------------------------------------------------------------------------------
	def clearFieldChasingUp(self):
		# Mise a zéro des champs
		self.chasingUpValues[0].set("")
		self.chasingUpValues[1].set(u"TE")
		self.chasingUpValues[2].set("")
		self.chasingUpModeCB.selectitem(0)
		# Affichage de la présence de Relance
		result = ChasingUp.select(ChasingUp.q.bill==self.listObject[self.index])
		count=0
		for row in result:
			count+=1
		if count < 2:
			self.field.set(str(count)+u" Relance")
		else:
			self.field.set(str(count)+u" Relances")

	def selectChasingUp(self, event=None):
		if self.listChasingUp.get(0)!="":
			result = ChasingUp.select(ChasingUp.q.id==self.idListChasingUp[int(self.listChasingUp.curselection()[0])])
			for row in result:
				self.selectedChasingUp = row
			#~ self.listObject[2]=self.selectedChasingUp.bill
			if self.selectedChasingUp.date != None:self.chasingUpValues[0].set(self.selectedChasingUp.date.strftime("%d/%m/%Y"))
			if self.selectedChasingUp.mode != None:self.chasingUpValues[1].set(self.selectedChasingUp.mode)                
			if self.selectedChasingUp.notes != None:self.chasingUpValues[2].set(self.selectedChasingUp.notes)
			# Affichage du Mode dans la ComboBox
			mode = ((u"TE", 0),(u"CS", 1),(u"CR", 2),(u"VI", 3),(u"RE", 4),)
			for n in mode:
				if n[0] == self.selectedChasingUp.mode: self.chasingUpModeCB.selectitem(n[1])              
			# activation du bouton supprimer
			self.deleteChasingUpBt.config(state=NORMAL)

	def searchChasingUp(self, event=None):
		self.listChasingUp.delete(0,END)
		self.idListChasingUp = []
		result = ChasingUp.select(ChasingUp.q.bill==self.listObject[self.index],orderBy=ChasingUp.q.date)
		for row in result:
			self.listChasingUp.insert(END, row.date.strftime("%d/%m/%Y")+" - "+row.mode)
			self.idListChasingUp.append(row.id)

	def makeChasingUp(self):
		leftLCFrame = Frame(self)
		Label(leftLCFrame, text=u"Relances").pack(side=TOP, fill=X)
		chasingUpLabels = (u"Date", u"Mode", u"Note")
		self.chasingUpValues = [StringVar(),StringVar(),StringVar()]
		chasingUpModeListCB = (u"Téléphone", u"Courrier simple", u"Courrier recommander", u"Visite", u"Recouvrement")
		count = 0
		for name in chasingUpLabels:
			f = Frame(leftLCFrame)
			Label(f, width=12, text=name, anchor=W).pack(side=LEFT)
			if count == 0: # Date
				Entry(f, textvariable=self.chasingUpValues[count], width=21).pack(side=LEFT, fill=X)
				myCal1=Button(f, image=self.imgCalendar, command=lambda x=self.chasingUpValues[count]:self.ctrlCalendar(x), padx=4, pady=1)
				myCal1.pack(side=LEFT) 
				self.balloon.bind(myCal1, u"Calendrier")
			elif count == 1: # Mode
				self.chasingUpModeCB=Pmw.ComboBox(f, selectioncommand=self.chasingUpMode, scrolledlist_items=chasingUpModeListCB, listheight=140)
				self.chasingUpModeCB._entryfield._entryFieldEntry.config( width = 21)
				self.chasingUpModeCB.pack(side=LEFT, fill=X)
				self.chasingUpModeCB.selectitem(0)
				self.chasingUpValues[count].set(u"TE")
			elif count == 2: # Notes
				Entry(f, textvariable=self.chasingUpValues[count], width=21).pack(side=LEFT, fill=X)
				myNotes=Button(f, image=self.imgNotes, command=lambda x=self.chasingUpValues[count]:self.ctrlNotes(x,u"Notes"), padx=4, pady=1)
				myNotes.pack(side=RIGHT)
				self.balloon.bind(myNotes, u"Détails de la note")
			else: 
				Entry(f, textvariable=self.chasingUpValues[count], width=23).pack(side=LEFT, fill=X)
			f.pack(side=TOP, fill=X)
			count += 1
		# Boutons enregistrement (new ou modify) et suppression
		s = Frame(leftLCFrame) 
		self.saveChasingUpBt=Button(s, image=self.imgSave, command=self.createChasingUp)
		self.saveChasingUpBt.bind("<Return>", self.createChasingUp)
		self.saveChasingUpBt.pack(side=LEFT)
		self.balloon.bind(self.saveChasingUpBt, u"Enregistrer")
		self.deleteChasingUpBt=Button(s, image=self.imgDelete, command=self.deleteChasingUp, state=DISABLED)
		self.deleteChasingUpBt.bind("<Return>", self.deleteChasingUp)
		self.deleteChasingUpBt.pack(side=LEFT)
		self.balloon.bind(self.deleteChasingUpBt, u"Supprimer")
		s.pack(side=TOP, fill=X)
		leftLCFrame.pack(side=LEFT, fill=X)
		# Liste des Lignes d'une pièce (présentation colonne de droite)
		rightLCFrame = Frame(self) 
		Label(rightLCFrame, text=u"Liste des Relances").pack(side=TOP, fill=X)
		s = Frame(rightLCFrame) 
		scrollbar = Scrollbar(s)
		scrollbar.pack(side=RIGHT, fill=Y)
		self.listChasingUp = Listbox(s)
		self.listChasingUp.config(yscrollcommand=scrollbar.set, width=50, selectmode=SINGLE, height=5)
		self.listChasingUp.bind("<ButtonRelease-1>",self.selectChasingUp)
		scrollbar.config(command=self.listChasingUp.yview)
		self.listChasingUp.pack()
		self.balloon.bind(self.listChasingUp, u"Séléctionner une lignes\npour le visualiser ou la modifier.")
		s.pack(side=TOP, fill=X)
		rightLCFrame.pack(side=RIGHT, fill=X)
		self.clearFieldChasingUp()
		self.searchChasingUp()

	def ctrlCalendar(self,field):
		CalendarGUI(field=field, log=self.log, path=self.path)

	def ctrlNotes(self,field,title):
		NotesGUI(field=field,title=title, log=self.log, path=self.path)

	def chasingUpMode(self, value):
		mode = ((u"TE", u"Téléphone"),(u"CS", u"Courrier simple"),(u"CR", u"Courrier recommander"),(u"VI", u"Visite"),(u"RE", u"Recouvrement"),)
		for n in mode:
			if n[1] == value: self.chasingUpValues[1].set(n[0])

	def getDateChasingUp(self):
		if self.chasingUpValues[0].get() != "":
			dt= self.chasingUpValues[0].get().split("/")
			d = datetime.date(int(dt[2]), int(dt[1]), int(dt[0]))
			return d
		else:
			return None

	def verifyChasingUp(self):
		if self.chasingUpValues[0].get() == "":
			showerror(u"Erreur de saisie", u"Le champ Date est obligatoire !\nMerci de le compléter.")
			return False        
		else:
			return True

	def createChasingUp(self, event=None):
		if self.verifyChasingUp():
			if  self.deleteChasingUpBt.config()["state"][4] == "normal":
				self.modifyChasingUp()
			else:
				if askyesno(u"Enregistrement", u"Souhaitez-vous enregistrer une nouvelle Relances au %s pour la pièce de vente en cours ?\n" % self.chasingUpValues[0].get()):
					ChasingUp(bill=self.listObject[self.index],
						date=self.getDateChasingUp(),
						mode=self.chasingUpValues[1].get().encode("utf-8"),
						notes=self.chasingUpValues[2].get().encode("utf-8"),
						createDate=datetime.datetime.now()
					)
				self.clearFieldChasingUp()
				self.searchChasingUp()

	def modifyChasingUp(self, event=None): 
		if askyesno(u"Modifier", u"Souhaitez-vous modifier la Relance du %s de la pièce de vente en cours ?" % self.selectedChasingUp.date):
			self.selectedChasingUp.date=self.getDateChasingUp()
			self.selectedChasingUp.mode=self.chasingUpValues[1].get().encode("utf-8")
			self.selectedChasingUp.notes=self.chasingUpValues[2].get().encode("utf-8")
		self.deleteChasingUpBt.config(state=DISABLED)
		self.clearFieldChasingUp()
		self.searchChasingUp()

	def deleteChasingUp(self, event=None): 
		if askyesno(u"Suppression", u"Souhaitez-vous supprimer la Relance du %s de la pièce de vente en cours ?\nCette opération est irréversible !" % self.selectedChasingUp.date):
			ChasingUp.delete(self.selectedChasingUp.id)
		self.deleteChasingUpBt.config(state=DISABLED)
		self.clearFieldChasingUp()
		self.searchChasingUp()
	# FIN de la gestion du module ChasingUp ---------------------------------------------------------------------------------------------------------